# -*- coding:utf-8 -*-

import redis

from typing import Iterable
from rediscluster import RedisCluster
from utils.constant import *


class SignalMeata:

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(SignalMeata, cls).__new__(cls)
        return cls._instance


class RedisConnBase(object):

    HOST = LOCAL_HOST
    PROT = LOCAL_PROT
    PASSWORD = LOCAL_PASSWORD
    DB = LOCAL_DB
    MAX_CONN = LOCAL_MAX_CONN

    def __str__(self) -> str: return super().__str__()

    def __init__(self, ex_redis_timeoout: int = 1 * 60, db=None):
        '''database 1 for fibtc'''

        self._pool = redis.ConnectionPool(host=self.HOST,
                                          port=self.PROT,
                                          password=self.PASSWORD,
                                          db=self.DB if not db else db,
                                          max_connections=self.MAX_CONN)

        self.r = redis.Redis(connection_pool=self._pool,
                             socket_timeout=3,
                             socket_connect_timeout=3)

        self.ex_redis_timeoout = ex_redis_timeoout

    def __getattr__(self, __o):

        return getattr(self.r, __o)


class StrictRedisCluster(object):

    def __init__(self, ex_redis_timeoout: int = 1 * 60, db=None):

        self.r = RedisCluster(startup_nodes=NODES, decode_responses=True)

    def __getattr__(self, __o):

        return getattr(self.r, __o)


class RedisConnect(SignalMeata):
    """
    depth:
    --------------------
        key ---> binance::depth::markets
        value ---> {"bids":[[price, amount],[]...]}
        SCARD key
    """

    def __init__(self):

        if SWITCH_NODES:
            self.conn = StrictRedisCluster()
        else:
            self.conn = RedisConnBase()

    def sadd(self, key, value):

        if not value:
            return

        if isinstance(value, Iterable) and not isinstance(value, str):
            self.conn.sadd(key, *value)
        else:
            self.conn.sadd(key, value)

    def scard(self, key):
        """
        return count
        """

        return self.conn.scard(key)

    def sismember(self, key, data):

        return self.conn.sismember(key, data)

    def smembers(self, key):

        value = self.conn.smembers(key)

        return list(map(lambda x:  x.decode("utf-8") if isinstance(x, bytes) else x, value))

    def srem(self, key, data):

        if not data:
            return
        if isinstance(data, Iterable) and not isinstance(data, str):
            self.conn.srem(key, *data)
        else:
            self.conn.srem(key, data)

    def set(self, key, value):

        self.conn.set(key, value)

    def get(self, key):

        self.conn.get(key)

    def zadd(self, key, value):
        """score default 1 """

        if not value:
            return
        if not isinstance(value, Iterable):
            self.conn.zadd(key, value)
        else:
            m = {x: 1 for x in value}
            self.conn.zadd(key, m)

    def zrange(self, key):
        """all members default"""

        value = self.conn.zrange(key, 0, -1)

        return list(map(lambda x:  x.decode("utf-8") if isinstance(x, bytes) else x, value))

    def zcard(self, key):
        """all members count"""

        return self.conn.zcard(key)

    def zrem(self, key, value):
        """delete members"""

        if not value:
            return

        if isinstance(value, Iterable) and not isinstance(value, str):
            self.conn.zrem(key, *value)
        else:
            self.conn.zrem(key, value)

    def keys(self, key):
        """all keys pattern """

        value = self.conn.keys(key)
        data = list(map(lambda x:  x.decode("utf-8")
                    if isinstance(x, bytes) else x, value))

        return data, len(data)

    def delete(self, key):
        """ """

        self.conn.delete(key)


if __name__ == "__main__":
    pass
